home *** CD-ROM | disk | FTP | other *** search
/ Amiga News 96 / Amiga News 96.iso / amig_ad_os / laurent_faillie / lfcinter / lfci_cal.cxx < prev    next >
Text File  |  1977-12-31  |  26KB  |  591 lines

  1. /***************************************************************************\
  2. *  LFCI_cal.cxx                                                             *
  3. *  Projet : LFCInter                                                        *
  4. *      © LFSoft 1995-96                                                     *
  5. *                                                                           *
  6. *  Evaluation d'une expression.                                             *
  7. *                                                                           *
  8.  ***************************************************************************
  9. *                                                                           *
  10. *   BNF (théorique) pour évaluer une expression C                           *
  11. *                                                                           *
  12. * (-11) expression ::= exp_affect {[, exp_affect ]}                         *
  13. *   Le résultat de l'expression est la valeur de la derniere exp_affect.    *
  14. *                                                                           *
  15. * (-10) exp_affect ::= exp_un opp_aff exp_affect                            *
  16. *                  ::= expr_cond                                            *
  17. *                                                                           *
  18. *   avec opp_aff '=','*=','/=','%=','+=','-=','&=','^=','|=','<<=','>>='    *
  19. *        exp_un doit être une référence.                                    *
  20. *                                                                           *
  21. * (-9)  expr_cond ::= exp_OU_log ? exp_OU_log : expr_cond                   *
  22. *                 ::= exp_OU_log                                            *
  23. *                                                                           *
  24. * (-8)  exp_OU_log ::= exp_OU_log || exp_ET_log                             *
  25. *                  ::= exp_ET_log                                           *
  26. *                                                                           *
  27. * (-7)  exp_ET_log ::= exp_ET_log && exp_OU_incl                            *
  28. *                  ::= exp_OU_incl                                          *
  29. *                                                                           *
  30. * (-6)  exp_OU_incl ::= exp_OU_incl | exp_OU_excl                           *
  31. *                   ::= exp_OU_excl                                         *
  32. *                                                                           *
  33. * (-5)  exp_OU_excl ::= exp_OU_excl ^ exp_ET                                *
  34. *                   ::= exp_ET                                              *
  35. *                                                                           *
  36. * (-4)  exp_ET ::= exp_ET & exp_egal                                        *
  37. *              ::= exp_egal                                                 *
  38. *                                                                           *
  39. * (-3)  exp_egal ::= exp_egal == exp_rel                                    *
  40. *                ::= exp_egal != exp_rel                                    *
  41. *                ::= exp_rel                                                *
  42. *                                                                           *
  43. * (-2)  exp_rel ::= exp_rel opp_rel exp_dcl                                 *
  44. *               ::= exp_dcl                                                 *
  45. *                                                                           *
  46. *   avec opp_rel '<','>','<=','>='                                          *
  47. *                                                                           *
  48. * (-1)  exp_dcl ::= exp_dcl >> exp_add                                      *
  49. *               ::= exp_dcl << exp_add                                      *
  50. *               ::= exp_add                                                 *
  51. *                                                                           *
  52. * (0)   exp_add ::= exp_add + exp_mul                                       *
  53. *               ::= exp_add - exp_mul                                       *
  54. *               ::= exp_mul                                                 *
  55. *                                                                           *
  56. * (1)   exp_mul ::= exp_mul * exp_un                                        *
  57. *               ::= exp_mul / exp_un                                        *
  58. *               ::= exp_mul % exp_un                                        *
  59. *               ::= exp_un                                                  *
  60. *                                                                           *
  61. * (2)   exp_un ::= opp_un exp_un                                            *
  62. *              ::=  exp_posf                                                *
  63. *                                                                           *
  64. *   avec opp_un '++','--','&','*','+','-','~','!'                           *
  65. *                                                                           *
  66. * (3)   exp_posf ::= exp_prim                                               *
  67. *                ::= exp_posf++                                             *
  68. *                ::= exp_posf--                                             *
  69. *                ::= exp_posf [expr_cond]{[expr_cond]}                      *
  70. *                                           Valeur d'un tableau             *
  71. *                                                                           *
  72. * (4)   exp_prim ::= valeur_littéral                                        *
  73. *                ::= variable                                               *
  74. *                ::= fonction (...)         Appel de fonction               *
  75. *                ::= ( exp_affect )                                         *
  76. *                                                                           *
  77. *    Cette BNF est INSPIREE de celle fournie avec le BORLAND (ansi ?) avec  *
  78. *   quelques modifications:                                                 *
  79. *       - l'opérateur 'sizeof' est traité comme une fonction et DOIT avoir  *
  80. *   son argument entre parenthèses -> Il a donc la même priorité que les    *
  81. *   autres fonctions...                                                     *
  82. *       - L'appel de fonction fait partie exp_prim (priorité la plus haute) *
  83. *   au lieu de exp_posf: Le tableau des priorités du BORLAND indique une    *
  84. *   priorité des appels sur les expressions post-fixé mais pas la BNF (!)   *
  85. *   qui les place au même niveau => Erreur dans BNF !                       *
  86. *       - La BNF place les [] et les opérateurs postfixés à la même         *
  87. *   priorité. le tableau des associativités ne distingue pas les opérateurs *
  88. *   préfixés des postfixés '++' et '--' et les places donc à une priorité   *
  89. *   inférieure par rapport à []. A mon avis, ce doit être une erreur de ce  *
  90. *   tableau: Tout les opérateurs post-fixés, y compris [], doivent avoir la *
  91. *   même priorité et être lus de gauche à droite...                         *
  92. *                                                                           *
  93. *   J'aurai préféré utiliser le BNF de GCC mais je n'ai pas réussi à la     *
  94. *   trouver (bon, c'est vrai que je n'ai pas trop cherché!). Je n'ai pas    *
  95. *   non plus vérifié certaines priorités ... étranges genre que les         *
  96. *   opérateurs <, <=, >=, ou > ont priorité sur == & != ou que && a         *
  97. *   priorité sur ||.                                                        *
  98. *                                                                           *
  99. *    Dans le code, plutôt que d'utiliser un code adapté de cette BNF, j'ai  *
  100. *   utilisé un remix entre la méthode des priorités des opérateurs et       *
  101. *   l'utilisation d'une "BNF restreinte". C'est plus simple à programmer, à *
  102. *   maintenir et, surtout, c'est beaucoup plus rapide !                     *
  103. *                                                                           *
  104. *    Voici donc la BNF restreinte utilisée dans ce programme:                *
  105. *                                                                           *
  106. *       reponse ::= exp_aff {, exp_aff}                                     *
  107. *   codé dans la fonction eval().                                           *
  108. *                                                                           *
  109. *       exp_aff ::= reférence {oppaff exp_cond}                             *
  110. *       exp_aff ::= exp_cond                                                *
  111. *   codé dans la fonction affectation().                                    *
  112. *                                                                           *
  113. *       exp_cond ::= exp_binaire ? exp_cond : exp_cond                      *
  114. *       exp_cond ::= exp_binaire                                            *
  115. *   codé dans la fonction conditionnel().                                   *
  116. *                                                                           *
  117. *       exp_binaire ::= exp_un {[opérateur_binaire exp_un]}                 *
  118. *   codé dans la fonction binaire(). Cette fonction gère elle-même la       *
  119. *   priorité des opérateurs binaires.                                       *
  120. *                                                                           *
  121. *       exp_un ::= [{pré-opérateur}] exp_posf                               *
  122. *   codé dans la fonction lectunaire().                                     *
  123. *                                                                           *
  124. *       exp_posf ::= exp_prim [{post-opérateur}]                            *
  125. *   codé dans la fonction lectunaire().                                     *
  126. *                                                                           *
  127. *       exp_prim ::= valeur_littéral                                        *
  128. *                ::= variable                                               *
  129. *                ::= fonction (...)         Appel de fonction               *
  130. *                ::= ( exp_affect )                                         *
  131. *   codé dans la fonction CalcLexer().                                      *
  132. *                                                                           *
  133. *       ON N'EST PAS CHEZ MICRO-SUCKER, l'optimisation, ça existe !!        *
  134. *                                                                           *
  135. *    Le type de valeur 'R' pour 'référence', qui est physiquement un        *
  136. *   pointeur, est utilisé pour représenter les 'lvalues':                   *
  137. *       - Si l'opérateur suivant est une affectation, la valeur pointée     *
  138. *       est modifiée (affectation),                                         *
  139. *       - Sinon, la valeur pointée est placée dans la pile...               *
  140. *                                                                           *
  141. *    Le type de valeur 'X', basé sur le type 'I', contient la valeur d'un   *
  142. *   token lu par la fonction CalcLexer().                                   *
  143. *                                                                           *
  144. \*************** Voir LFCInter pour plus d'informations ********************/
  145.  
  146. #include "LFCInter.h"
  147. #include "LFCI_icl.h"
  148.  
  149.     /*
  150.      *   Stockage des chaînes lues dans le source. Grâce à ceci, une chaîne
  151.      *  n'est décodée qu'une seule fois si le source repasse au même endroit...
  152.      */
  153.  
  154. static struct _stkchaine : public string {
  155.     _stkchaine(const char *aptr) : ptr(aptr){};
  156.  
  157.     const char *ptr; // Valeur du pointeur de début de la chaîne
  158.     const char *apres; // Valeur du pointeur après lecture de la chaîne
  159.     _stkchaine *suivant;
  160. } *premier = NULL;
  161.  
  162. _rep lectcar(const char **ptr){
  163. /*  Ne lit qu'un seul caractère placé entre ''
  164.  *  <- ptr pointe sur caractère lui-même
  165.  *  -> ptr pointe sur le dernier caractère pris en compte
  166.  */
  167.     if(**ptr == '\n' || !*ptr){
  168.         cerr << "*E* Ligne " << calcligne(*ptr) << ": Déclaration de caratère non terminée.\n";
  169.         exit(5);
  170.     }
  171.  
  172.     if(**ptr == '\\'){ // Caractère qualifié
  173.         ++*ptr; // Saute '\'
  174.         switch(**ptr){
  175.         case '\n':
  176.         case 0:
  177.             cerr << "*E* Ligne " << calcligne(*ptr) << ": Déclaration de caratère non terminée.\n";
  178.             exit(5);
  179.         case 'a':   // BEL
  180.             return (char)'\a';
  181.         case 'b':   // BS
  182.             return (char)'\b';
  183.         case 'f':   // FF
  184.             return (char)'\f';
  185.         case 'n':   // LF
  186.             return (char)'\n';
  187.         case 'r':   // CR
  188.             return (char)'\r';
  189.         case 't':   // HT
  190.             return (char)'\t';
  191.         case 'v':   // VT
  192.             return (char)'\v';
  193.         case 'x':
  194.         case 'X':{  // Lecture d'un caractère mis sous forme héxa
  195.                 unsigned char i=0;
  196.                 while( isxdigit(*++*ptr) ){
  197.                     i *= 16;
  198.                     if(isdigit(**ptr))
  199.                         i += **ptr - '0';
  200.                     else
  201.                         i += tolower(**ptr) - 'a' + 10;
  202.                 }
  203.                 --*ptr; // Retour sur le dernier caractère prise en compte
  204.                 return (char) i;
  205.             }
  206.         default:
  207.             if(isodigit(**ptr)){ // Peut être une constante octale
  208.                 unsigned char i=0;
  209.  
  210.                 do
  211.                     i = i*8 + **ptr - '0';
  212.                 while( isodigit(*++*ptr) );
  213.  
  214.                 --*ptr; // Retour sur le dernier caractère prise en compte
  215.                 return (char)i;
  216.             } else // Juste un caractère qui ne doit pas être interprété
  217.                 return **ptr;
  218.         }
  219.     } else if(**ptr == '\''){ // Lecture d'un caractère nul ''
  220.         --*ptr; // Pas de caractère pris en compte, mais on doit quant même revenir en arriere!
  221.         return (char)0;
  222.     } else // Simplement un caractère
  223.         return **ptr;
  224. }
  225.  
  226. static _rep trouvechaine(_token &ptr){
  227. /* Lecture d'une chaîne: Si ptr fait déjà partie de la liste, la chaîne stockée
  228.  * est renvoyée et ptr prend la valeur 'après'
  229.  */
  230.     _stkchaine *t;
  231.  
  232.     for(t=premier;t;t=t->suivant){
  233. #ifdef __BCPLUSPLUS__
  234.         if(string(t->ptr) == ptr){ // La chaîne a déjà été stockée
  235. #else
  236.         if(t->ptr == ptr){ // La chaîne a déjà été stockée
  237. #endif
  238.             ptr = t->apres;
  239.             return _rep((void *)t->c_str(),'*',"C");
  240.         }
  241.     }
  242.  
  243.         // C'est une nouvelle chaîne
  244.     t = new _stkchaine(ptr);
  245.     if(!t){
  246.         cerr << "*F* Ligne " << calcligne(ptr) << ": Manque de mémoire pour stocker une chaîne.\n";
  247.         exit(10);
  248.     }
  249.  
  250. tchn_autre:
  251.     const char *x=ptr;
  252.  
  253.     for(++x; *x!='"'; ++x){
  254.         if(*x=='\n' || !*x){
  255.             cerr << "*E* Ligne " << calcligne(x) << ": Chaîne non terminée " << ADEB("(trouvechaine:1)" << ) ".\n";
  256.             exit(5);
  257.         }
  258.  
  259.         if(*x == '\\'){
  260.             *t += lectcar(&x).val.caractere; // Stochage du caractère
  261.             continue;
  262.         }
  263.         *t += *x;
  264.     }
  265.  
  266.         // Recherche si la chaîne se poursuit "ch1" "ch2" -> "ch1ch2"
  267.     ptr = x;
  268.     ptr++; // Saute le '"' fermant
  269.  
  270.     if(*ptr == '"')
  271.         goto tchn_autre;
  272.  
  273.     t->apres = ptr;
  274.     t->suivant = premier;
  275.     premier = t;
  276.  
  277.     return _rep((void *)t->c_str(),'*',"C");
  278. }
  279.  
  280.     /*  Au lieu d'utiliser des valeurs par défaut pour les arguments optionnels,
  281.      * rch_op() est surchargé pour accélérer sont fonctionnement !
  282.      */
  283.  
  284. static const _operateur *rch_op(int op){
  285. /*  Recherche la PREMIERE structure associée avec l'opérateur passé en argument
  286.  *  -> NULL en cas d'erreur
  287.  */
  288.     int i;
  289.  
  290.     for(i=0; operateur[i].op; i++)
  291.         if(operateur[i].op == op)
  292.             return &operateur[i];
  293.  
  294.     return NULL;
  295. }
  296.  
  297. static const _operateur *rch_op(int op, bool unaire){
  298. /*  Recherche la structure associée avec l'opérateur passé en argument
  299.  * tient compte si l'operateur est unaire ou binaire.
  300.  *  -> NULL en cas d'erreur
  301.  */
  302.     int i;
  303.  
  304.     for(i=0; operateur[i].op; i++)
  305.         if(operateur[i].op == op && unaire == operateur[i].unaire)
  306.             return &operateur[i];
  307.  
  308.     return NULL;
  309. }
  310.  
  311. static const _operateur *rch_op(int op, bool unaire, bool devant){
  312. /*  Recherche la structure associée avec l'opérateur passé en argument
  313.  * tient compte si l'operateur est unaire ou binaire, sa position (uniquement
  314.  * pour les opérateurs unaires).
  315.  *  -> NULL en cas d'erreur
  316.  */
  317.     int i;
  318.  
  319.     for(i=0; operateur[i].op; i++)
  320.         if(operateur[i].op == op && unaire == operateur[i].unaire){
  321.             if( unaire && operateur[i].devant == devant )
  322.                 return &operateur[i];
  323.         }
  324.  
  325.     return NULL;
  326. }
  327.  
  328. static _rep CalcLexer(_token &ptr, _tablesmb *table_locale, bool sansfonc=false){
  329. /* Cette fonction est une interface entre les méthodes de _token et eval(),
  330.  * elle lit l'élément suivant de l'expression et renvoie:
  331.  *  <- un 'L' si c'est une valeur litérale,
  332.  *  <- si c'est une variable, une référence sur celle-ci,
  333.  *  <- la valeur de retour dans le cas d'une fonction (après l'avoir appelée)
  334.  *  <- un 'X' s'il s'agit d'un token ou d'un autre caractère
  335.  *
  336.  *  -> ptr est incrémenté et len contiendra la longueur du token lu suivant les
  337.  * même règles que dans LFCI_Lex/trouvetoken(); sauf que ptr est directement
  338.  * incrémenté s'il s'agit d'un symbole qui est lu.
  339.  *  -> sansfonc == true si les éventuelles fonctions trouvées provoquent une
  340.  * erreur au lieu d'être exécutée.
  341.  */
  342.  
  343.     if(*ptr == smbl_id){ // On lit un identifieur
  344.         _var *symbole = trouve_symbole(table_locale, ptr.obj());
  345.  
  346.         if(!symbole){
  347.             cerr << "*E* Ligne " << calcligne(ptr) << ": Symbole inconnu '" << ptr.obj() << "'\n";
  348.             exit(5);
  349.         }
  350.  
  351.         ptr++;
  352.         if(symbole->type[0] == 'F'){
  353.                 // Si le symbole suivant est un '(' /*)*/ il faut exécuter la fonction
  354.             if(*ptr=='(' /*)*/ ){
  355.                 if(sansfonc){
  356.                     cerr << "*E* Ligne " << calcligne(ptr) << ": Erreur de syntaxe pour '" << ptr.obj() << "' !\n";
  357.                     exit(5);
  358.                 } else { // C'est une fonction: Il faut l'exécuter
  359.                     ptr++;
  360.                     return lancefonc(ptr, (_var_fonc *)symbole, table_locale);
  361.                 }
  362.             } else
  363.                 return symbole->repval(ptr); // Sinon on renvoie la représentation de la fonction
  364.         }
  365.         return _rep(symbole->refval(), 'R', symbole->type); // C'est une variable, on renvoie sa référence
  366.     } else if(*ptr == '0'){
  367.         long i=0;
  368.         const char *p=ptr;
  369.         p++; // Ne pas mettre le ++ dans le tolower() car cette macro peut utiliser plusieurs fois son argument
  370.         if(tolower(*p) == 'x'){ // Lecture d'un nombre hexa
  371.             while(isxdigit(*++p)){
  372.                 i *= 16;
  373.                 if(isdigit(*p))
  374.                     i += *p - '0';
  375.                 else
  376.                     i += tolower(*p) - 'a' + 10;
  377.             }
  378.         } else { // Lecture d'un octal
  379.             while( isodigit(*p) ){
  380.                 i = i*8 + *p - '0';
  381.                 p++;
  382.             }
  383.         }
  384.         ptr = p;
  385.         return _rep(i);
  386.     } else if(isdigit(*ptr)){ // On lit une valeur numérique
  387.         long i=0;
  388.         const char *p = ptr;
  389.  
  390.         do {
  391.             i = i*10 + *p -'0';
  392.         } while( isdigit(*++p) );
  393.         ptr = p;
  394.         return _rep(i);
  395.     } else if(*ptr == '"') // On lit une chaîne
  396.         return trouvechaine(ptr);
  397.     else if(*ptr == '\''){ // Lecture d'un caractère
  398.         const char *x = ptr; // On ne peut pas utiliser _token sinon, par exemple, les espaces seront sautés
  399.         x++; // Saute le "'"
  400.         _rep t=lectcar(&x);
  401.         if(*++x != '\''){
  402.             cerr << "*E* Ligne " << calcligne(ptr) << ": Impossible de trouver le \"'\" fermant !\n";
  403.             exit(5);
  404.         }
  405.         ptr=++x;
  406.         return t;
  407.     } else if(*ptr == '(' /*)*/ ){ // Parenthèses
  408.         ptr++;
  409.         _rep t=eval(ptr, table_locale);
  410.         ptr++; // Saute le #(# ')' de fermeture
  411.         return t;
  412.     } else if( ptr.interne() )
  413.         if(sansfonc){
  414.             cerr << "*E* Ligne " << calcligne(ptr) << ": Erreur de syntaxe pour '" << ptr.obj() << "' !\n";
  415.             exit(5);
  416.         } else
  417.             return interne(ptr,table_locale);
  418.     else { // C'est un autre caractère
  419.         _rep t = _rep(*ptr,'X');
  420.         ptr++;
  421.         return t;
  422.     }
  423. }
  424.  
  425. static _rep lectunaire(_token &ptr, _tablesmb *table_locale){
  426. /* Lecture d'une valeur "unaire".
  427.  * A la sortie, ptr pointe sur la premiere valeur non reconnue
  428.  * Voir eval() pour plus d'informations sur les arguments.
  429.  *
  430.  *  BNF restreinte de l'expression attendu par cette fonction:
  431.  *
  432.  *      reponse ::= [{pré-opérateur}] exp_prim [{post-opérateur}]
  433.  *
  434.  *  notez que cette fonction s'attend à lire au moins exp_prim !
  435.  *
  436.  *  Comme tous les opérateurs unaires ont la même priorité et sont évalués de
  437.  *  droite à gauche, il n'y a qu'à les pousser dans la pile et effectuer les
  438.  *  calculs lors du dépilement.
  439.  */
  440.     LFDynaStack<_rep> valeurs;  // Pile des valeurs
  441.     LFDynaStack<const _operateur *> operateurs;   // Pile des opérateurs
  442.  
  443.     _rep suivant=CalcLexer(ptr,table_locale);
  444.  
  445.     while(suivant.type() == 'X'){ // Lecture des pré-opérateurs unaires
  446.         const _operateur *x = rch_op(suivant.val.entier,true,true);
  447.  
  448.         if(!x){
  449.             cerr << "*E* Ligne " << calcligne(ptr) << ": Le symbole avant '" << ptr.obj() << "' provoque une erreur de syntaxe.\n";
  450.             exit(5);
  451.         }
  452.  
  453.         operateurs.Push(x); // Tous les opérateurs unaires de devant ont les mêmes priorités
  454.  
  455.         suivant=CalcLexer(ptr,table_locale);
  456.     }
  457.  
  458.     valeurs.Push(suivant);
  459.     _token t;
  460.  
  461.     FOREVER{    // Lecture des post-opérateurs unaires
  462.         t=ptr;
  463.         suivant=CalcLexer(ptr,table_locale,true);
  464.  
  465.         if(suivant.type()!='X'){
  466.             cerr << "*E* Ligne " << calcligne(ptr) << ": Erreur de syntaxe lors d'un post-operateur unaire ("<< ptr.obj() << ").\n";
  467.             exit(5);
  468.         }
  469.  
  470.         const _operateur *x = rch_op(suivant.val.entier,true,false);
  471.  
  472.         if(!x){ // Ce n'est plus un post-opérateur
  473.             ptr = t; // Il faut donc restorer le pointeur
  474.             break;
  475.         }
  476.  
  477.         if(x->fonc) // C'est un opérateur
  478.             valeurs.Push(x->fonc(valeurs,ptr));
  479.         else {  // c'est un [] => resultat = *(adr + index)
  480.             valeurs.Push(conv('I',eval(ptr,table_locale),ptr));
  481.             if(*ptr != /*[*/ ']'){
  482.                 cerr << "*E* Ligne " << calcligne(ptr) << /*[*/ ": Impossible de trouver le ']' fermant.\n";
  483.                 exit(5);
  484.             }
  485.             ptr++;
  486.             valeurs.Push(plus(valeurs,ptr));
  487.             valeurs.Push(deref(valeurs,ptr));
  488.         }
  489.     }
  490.  
  491.     while(operateurs.length()>=0) // Exécution des calculs
  492.         valeurs.Push(operateurs.Pop()->fonc(valeurs,ptr));
  493.  
  494.     DEB(
  495.         if(valeurs.length()){ // Il ne doit en rester qu'un (highlander ?)
  496.             cerr << "*F* Ligne " << calcligne(ptr) << ": Il reste plus d'une valeur dans la pile à la sortie de LFCI_cal/lectunaire().\n";
  497.             exit(20);
  498.         }
  499.     );
  500.     return valeurs.Pop();
  501. }
  502.  
  503. static _rep binaire(_token &ptr, _tablesmb *table_locale){
  504. /* Lecture d'une valeur "binaire".
  505.  * Voir eval() pour plus d'informations sur les arguments.
  506.  *
  507.  *  BNF restreinte de l'expression attendue par cette fonction:
  508.  *
  509.  *      reponse ::= exp_un {[operateur exp_un]}
  510.  *
  511.  */
  512.     LFDynaStack<_rep> valeurs;  // Pile des valeurs
  513.     LFDynaStack<const _operateur *> operateurs;   // Pile des opérateurs
  514.  
  515.     FOREVER{
  516.         valeurs.Push(lectunaire(ptr,table_locale));
  517.  
  518.         const _operateur *x = rch_op(*ptr,false);
  519.         if(!x) break;
  520.         ptr++; // L'opérateur est accepté, on passe au symbole suivant...
  521.  
  522.     autres:
  523.         if(operateurs.length()>=0){ // Il y a déjà quelque chose dans la pile des opérateurs
  524.             if(operateurs[operateurs.length()]->priorite >= x->priorite){ // Il a priorité: On l'exécute
  525.                 valeurs.Push(operateurs.Pop()->fonc(valeurs,ptr));
  526.                 goto autres; // Peut-être que l'opérateur précédent est aussi à exécuter.
  527.             }
  528.         }
  529.         operateurs.Push(x);
  530.     }
  531.  
  532.     while(operateurs.length()>=0) // Exécution des calculs
  533.         valeurs.Push(operateurs.Pop()->fonc(valeurs,ptr));
  534.  
  535.     DEB(
  536.         if(valeurs.length()){ // Il ne doit en rester qu'un
  537.             cerr << "*F* Ligne " << calcligne(ptr) << ": Il reste plus d'une valeur dans la pile à la sortie de LFCI_cal/binaire().\n";
  538.             exit(20);
  539.         }
  540.     );
  541.  
  542.     return valeurs.Pop();
  543. }
  544.  
  545. _rep conditionnel(_token &ptr, _tablesmb *table_locale){
  546. /* Lecture d'une valeur "conditionnelle".
  547.  * Voir eval() pour plus d'informations sur les arguments.
  548.  *
  549.  *  BNF restreinte de l'expression attendu par cette fonction:
  550.  *       reponse ::= exp_binaire ? exp_cond : exp_cond
  551.  *       reponse ::= exp_binaire
  552.  */
  553.     _rep t = binaire(ptr,table_locale);
  554.  
  555.     return t;
  556. }
  557.  
  558. _rep eval(_token &ptr, _tablesmb *table_locale, bool un){
  559. /* Evaluation d'une expression.
  560.  * <- 'ptr' doit pointer sur le début de l'expression
  561.  *    table_locale est la table actuelle des symboles (NULL= uniquement la table globale)
  562.  *    'un' est vrai si une seule expression doit être lue, la présence d'un ','
  563.  *    ne provoque pas la lecture d'autres valeurs (par exemple dans le cas de
  564.  *    définitions de variables...). Note: Si 'un = 'false', la présence d'un ';'
  565.  *    comme premier caractère lu provoque le retour d'un void.
  566.  *
  567.  *  -> Renvoie la valeur représentant le resultat de l'expression
  568.  *     'ptr' pointe sur le premier caractère qui provoque une erreur de l'expression
  569.  *     (caractère inconnu, s'il s'agit d'une erreur de synstaxe de calcul genre
  570.  *      5 + %3, il y a directement une erreur).
  571.  *
  572.  *  BNF restreinte de l'expression attendu par cette fonction:
  573.  *
  574.  *      reponse ::= exp_aff {, exp_aff}
  575.  *
  576.  */
  577.     _rep t;
  578.  
  579.     if(!un && *ptr == ';') // C'est possible: Lecture de l'argument de return;
  580.         return _rep();
  581.  
  582.     t = affectation(ptr,table_locale);
  583.  
  584.     while(*ptr == ',' && !un){ // C'est un 'calcul multiple'
  585.         ptr++; // Saute le ','
  586.         t = affectation(ptr,table_locale);
  587.     }
  588.  
  589.     return t;
  590. }
  591.